package com.tjyx.common.dao;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.tjyx.common.TJYXException;
import com.tjyx.common.util.ReflectUtil;
import com.tjyx.common.util.db.JDBCTemplate;
import com.tjyx.common.util.db.SqlUtil;

/**
 * 数据访问对象DAO基类
 * 
 * 时间：2012-3-23
 * 
 * @author zhutianjie
 * @version v1.0
 * 
 */
public class BaseDao {

	/**
	 * JDBC操作模板方法
	 */
	private JDBCTemplate jdbcTemplate = null;
	
	public JDBCTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	public void setJdbcTemplate(JDBCTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	/**
	 * 设置查询起始位置
	 * @param startResult
	 */
	public void setStartResult(int startResult) {
		if(startResult > 1) {
			jdbcTemplate.getSelection().setFirstRow(startResult - 1);
		}
	}
	
	/**
	 * 设置查询结束位置
	 * @param endResult
	 */
	public void setEndResult(int endResult) {
		jdbcTemplate.getSelection().setMaxRows(endResult);
	}
	
	/**
	 * 带有可变参数(?,?,?...)的更新方法，用来完成增、删、改操作
	 * 
	 * @param sql
	 * @param parameters
	 * @return
	 * @throws TJYXException 
	 */
	public int update(String sql, Object... parameters) throws TJYXException {
		jdbcTemplate = new JDBCTemplate();
		return this.jdbcTemplate.update(sql, parameters);
	}

	/**
	 * 带有可变参数(?,?,?...)的查询方法
	 * 
	 * @param sql
	 * @param parameter
	 * @return
	 */
	public Map<String, Object> selectMap(String sql, Object...parameters) {
		jdbcTemplate = new JDBCTemplate();
		return this.jdbcTemplate.selectMap(sql, parameters);
	}

	/**
	 * 不带参数的查询方法，返回多条记录对应的集合
	 * 
	 * @param sql
	 * @return
	 */
	public List<Map<String, Object>> selectMapList(String sql,Object...parameters) {
		jdbcTemplate = new JDBCTemplate();
		return this.jdbcTemplate.selectMapList(sql,parameters);
	}
	
	
	/**
	 * 带有可变数量参数(?,?,?...)的查询方法，返回装载多个数据传输类的集合
	 * 
	 * @param <T> DTO类型
	 * @param sql sql查询语句
	 * @param clazz 数据传输类DTO
	 * @param parameters 可变长度参数
	 * @return
	 */
	public <T> List<T> selectObjectList(String sql, Class<T> clazz,
			Object... parameters) {
		jdbcTemplate = new JDBCTemplate();
		return this.jdbcTemplate.selectObjectList(sql, clazz, parameters);
	}
	
	/**
	 * 根据"属性-值"和DTO Class量查询装载多个DTO的集合
	 * @param <T> DTO类型
	 * @param clazz DTO类信息
	 * @param sqlMap 用于构造sql的"属性-值"map
	 * @return
	 * @throws TJYXException
	 */
	public <T> List<T> selectObjectList(Class<T> clazz, String tableName,Map<String,Object> sqlMap) throws TJYXException {
		jdbcTemplate = new JDBCTemplate();
		String sql = SqlUtil.createSql4SingleTable(tableName,sqlMap);
		Object[] parameters = sqlMap.values().toArray();
		return this.jdbcTemplate.selectObjectList(sql, clazz, parameters);
	}
	
	/**
	 * (分页查询)<br />
	 * 根据"属性-值"和DTO Class量查询装载多个DTO的集合
	 * @param <T> DTO类型
	 * @param clazz DTO类信息
	 * @param sqlMap 用于构造sql的"属性-值"map
	 * @return
	 * @throws TJYXException
	 */
	public <T> List<T> selectObjectList4Pagination(int startRow,int endRow,Class<T> clazz, String tableName,Map<String,Object> sqlMap) throws TJYXException {
		jdbcTemplate = new JDBCTemplate();
		String orderSql = null;
		if(sqlMap.containsKey("desc")) {
			String id2sort = (String)sqlMap.get("desc");
			orderSql = "order by o." + id2sort + " desc";
			sqlMap.remove("desc");
		}
		String sql = SqlUtil.createSql4SingleTable(tableName,sqlMap);
		sql += orderSql;
		Object[] parameters = sqlMap.values().toArray();
		this.setStartResult(startRow);
		this.setEndResult(endRow);
		return this.jdbcTemplate.selectObjectList(sql, clazz, parameters);
	}
	
	/**
	 * 根据ID值查询单个对象
	 * @param <T>
	 * @param sql
	 * @param clazz
	 * @param id
	 * @return
	 * @throws TJYXException 
	 */
	public <T> T selectObjectById(Class<T> clazz,String tableName,Long id) throws TJYXException {
		jdbcTemplate = new JDBCTemplate();
		Map<String,Object> sqlMap = new HashMap<String,Object>();
		sqlMap.put("id", id);
		List<T> list = this.selectObjectList(clazz, tableName, sqlMap);
		if(list.size() > 0) {
			return list.get(0);
		}
		return null;
		
	}
	
	/**
	 * 根据"属性-值"和DTO Class量查询总数
	 * 
	 * @param <T> DTO类型
	 * @param clazz DTO类信息
	 * @param sqlMap 用于构造sql的"属性-值"map
	 * @return
	 * @throws TJYXException
	 */
	public int selectCounter4Pagination(String tableName,Map<String,Object> sqlMap) throws TJYXException {
		jdbcTemplate = new JDBCTemplate();
		jdbcTemplate = new JDBCTemplate();
		if(sqlMap.containsKey("desc")) {
			throw new TJYXException("sqlMap中存在\"desc\"属性,请先执行记录查询后再进行统计");
		}
		String sql = SqlUtil.createCounter4SingleTable(tableName,sqlMap);
		Object[] parameters = sqlMap.values().toArray();
//		this.setFirstResult(page);
//		this.setMaxResult(rows);
		Map<String, Object> map = this.jdbcTemplate.selectMap(sql,parameters);
		Long counter = (Long)map.get("count(*)");
		return counter.intValue();
		
	}
	
	
	/**
	 * 根据id值批量删除
	 * @param ids 
	 * @throws TJYXException 
	 */
	public void deleteByIds(String tableName,String[] ids) throws TJYXException {
		jdbcTemplate = new JDBCTemplate();
		String sql = null;
		StringBuilder sqlBuilder = new StringBuilder("delete from ");
		sqlBuilder.append(tableName);
		sqlBuilder.append(" where id in (");
		StringBuilder parametersBuilder = new StringBuilder();
		for(int i = 0; i < ids.length; i++) {
			if(i == ids.length - 1) {
				parametersBuilder.append("?");
			} else {
				parametersBuilder.append("?,");
			}
		}
		sqlBuilder.append(parametersBuilder);
		sqlBuilder.append(")");
		sql = sqlBuilder.toString();
		System.out.println(sql);
		this.update(sql, ids);
	}
	
	
	/**
	 * 保存数据传输对象
	 * 
	 * @param <T> 对象类型
	 * @param t 对象实例
	 * @param clazz 对象类型信息
	 * @throws TJYXException 
	 */
	public <T> void saveObject(T t, String tableName) throws TJYXException {
		jdbcTemplate = new JDBCTemplate();
		Class<T> clazz = (Class<T>) t.getClass();
		List<Object> conditionsList = new ArrayList<Object>();
		Field[] fields = clazz.getDeclaredFields();
		for(int i = 0; i < fields.length; i++) {
			if(fields[i].getName() != "serialVersionUID") { //过滤序列化信息
				Method getMethod = ReflectUtil.createGetMethod(fields[i], clazz);
				try {
					Object obj = getMethod.invoke(t);
					conditionsList.add(obj);
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			}
		}
		String sql = SqlUtil.createSaveSql4SingleTable(tableName, clazz);
		System.out.println(sql);
		this.update(sql, conditionsList.toArray());
	}
	
	/**
	 * 更新单个对象
	 * 
	 * @param <T> 对象泛型
	 * @param t 被更新的对象
	 * @param tableName 表名
	 * @throws TJYXException
	 */
	public <T> void updateObject(T t, String tableName) throws TJYXException {
		jdbcTemplate = new JDBCTemplate();
		Class<T> clazz = (Class<T>) t.getClass();
		List<Object> conditionsList = new ArrayList<Object>();
		Long id = 0L;
		Map<String,Object> attrsMap = new LinkedHashMap<String,Object>();
		Field[] fields = clazz.getDeclaredFields();
		for(int i = 0; i < fields.length; i++) {
			if(fields[i].getName() != "serialVersionUID") { //过滤序列化信息
				Method getMethod = ReflectUtil.createGetMethod(fields[i], clazz);
				try {
					Object obj = getMethod.invoke(t);
					if(obj != null) {
						if("id".equals(fields[i].getName())){
							id = (Long)obj;
						} else {
							attrsMap.put(fields[i].getName(), obj);
							conditionsList.add(obj);
						}
					}
					
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			}
		}
		String sql = SqlUtil.createUpdate4SingleTable(tableName, attrsMap);
		System.out.println(sql);
		if(id == 0L) {
			throw new TJYXException("DTO的Id值不能为空");
		} else {
			conditionsList.add(id);
		}
		this.update(sql, conditionsList.toArray());
	}
	
}
